#pragma once

#include "opt.h"
#include "geometry.h"
#include "SurfaceInputState.h"
#include "GL/glut.h"

#include <fstream>
#include <sstream>

class Surface {
private:
    static const unsigned int bufferSize = 256;
    int level;

    Surface();

    static Eigenstructure* eigenstructures;

    void addVertex(const Vector3d& pos, int sharpness, bool opt);
    void addVertex(Vertex* v);

    void addEdge(Edge* e);
    Edge* addEdge(int a, int b, int sharpness, bool opt);

    void setEdge(int a, int b, Face* face);

    //adds a face, plus all associated edges
    void addFace(const vector<int>& vertexIndices, int sharpness, bool opt);
    void addFace(const vector<Vertex*>& faceVertices, int sharpness, bool opt);

    void processLine(const char* s, SurfaceInputState& state);

    void op_v(stringstream& ss, SurfaceInputState& state);
    void op_e(stringstream& ss, SurfaceInputState& state);
    void op_f(stringstream& ss, SurfaceInputState& state);
    void op_sharpness(stringstream& ss, SurfaceInputState& state);
    void op_opt(stringstream& ss, SurfaceInputState& state);

public:
    static void useEigenstructures(Eigenstructure* e);

    //constructor from obj file
    Surface(const char* filename);

    void calculateCurvatures();
    void writeObj(const char* filename, bool extended = false, double curvatureScale = 0.0) const;

    //destructor; deletes all geometry
    ~Surface();

    vector<Vertex*> vertices;
    vector<Edge*> edges;
    vector<Face*> faces;

    //Creates a new surface from this one via Catmull-Clark subdivision.
    Surface* cc() const;

    Surface* ccLimit() const;

    void surfaceGeometry(bool useMeanCurvature) const;
    void normalGeometry() const;

    void opt(const char* optType, int n);
};
